//
// (C) Copyright 2009 Irantha Suwandarathna (irantha@gmail.com)
// All rights reserved.
//

/* Copyright (c) 2001-2008, The HSQL Development Group
 * All rights reserved.
 *
 * Redistribution and use _in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions _in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer _in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the HSQL Development Group nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


using System;
using EffiProz.Core.DataTypes;
using EffiProz.Core.Lib;
using EffiProz.Core.ScriptIO;
using EffiProz.Core.Errors;


namespace EffiProz.Core.RowIO
{
    /**
     *  Class for reading the data for a database row from the script file.
     *
     * @author fredt@users
     * @version 1.8.0
     * @since 1.7.3
     */
    public class RowInputTextLog : RowInputBase
    , RowInputInterface
    {
        Scanner scanner;
        String tableName = null;
        String schemaName = null;
        int statementType;
        Object value;

        public RowInputTextLog()
            : base(new byte[0])
        {

            scanner = new Scanner();
        }

        public void setSource(String text)
        {

            scanner.reset(text);

            statementType = ScriptReaderBase.ANY_STATEMENT;

            scanner.scanNext();

            String s = scanner.getString();

            if (s.Equals(Tokens.T_INSERT))
            {
                statementType = ScriptReaderBase.INSERT_STATEMENT;

                scanner.scanNext();
                scanner.scanNext();

                tableName = scanner.getString();

                scanner.scanNext();
            }
            else if (s.Equals(Tokens.T_DELETE))
            {
                statementType = ScriptReaderBase.DELETE_STATEMENT;

                scanner.scanNext();
                scanner.scanNext();

                tableName = scanner.getString();
            }
            else if (s.Equals(Tokens.T_COMMIT))
            {
                statementType = ScriptReaderBase.COMMIT_STATEMENT;
            }
            else if (s.Equals(Tokens.T_SET))
            {
                scanner.scanNext();

                if (Tokens.T_SCHEMA.Equals(scanner.getString()))
                {
                    scanner.scanNext();

                    schemaName = scanner.getString();
                    statementType = ScriptReaderBase.SET_SCHEMA_STATEMENT;
                }
            }
        }

        public int getStatementType()
        {
            return statementType;
        }

        public String getTableName()
        {
            return tableName;
        }

        public String getSchemaName()
        {
            return schemaName;
        }

        protected void readField()
        {

            readFieldPrefix();
            scanner.scanNext();

            value = scanner.getValue();
        }

        protected void readNumberField(SqlType type)
        {

            readFieldPrefix();
            scanner.scanNext();

            bool minus = scanner.getTokenType() == Tokens.MINUS;

            if (minus)
            {
                scanner.scanNext();
            }

            value = scanner.getValue();

            if (minus)
            {
                try
                {
                    value = ((NumberType)scanner.getDataType()).negate(value);
                }
                catch (CoreException ) { }
            }
        }

        protected void readFieldPrefix()
        {

            scanner.scanNext();

            if (statementType == ScriptReaderBase.DELETE_STATEMENT)
            {
                scanner.scanNext();
                scanner.scanNext();
            }
        }

        public override String readString()
        {

            readField();

            return (String)value;
        }

        public override short readShort()
        {
            throw Error.runtimeError(ErrorCode.U_S0500, "");
        }

        public override int readInt()
        {
            throw Error.runtimeError(ErrorCode.U_S0500, "");
        }

        public override long readLong()
        {
            throw Error.runtimeError(ErrorCode.U_S0500, "");
        }

        public override int readType()
        {
            return 0;
        }

        protected override bool checkNull()
        {

            // Return null on each column read instead.
            return false;
        }

        protected override String readChar(SqlType type)
        {

            readField();

            return (String)value;
        }

        protected override int? readSmallint()
        {

            readNumberField(SqlType.SQL_SMALLINT);
            if (value == null)
                return null;

            return Convert.ToInt32(value);
        }

        protected override int? readInteger()
        {

            readNumberField(SqlType.SQL_INTEGER);
            if (value == null)
                return null;

            return Convert.ToInt32(value);
        }

        protected override long? readBigint()
        {

            readNumberField(SqlType.SQL_BIGINT);

            if (value == null)
            {
                return null;
            }

            return Convert.ToInt64(value);
        }

        protected override double? readReal()
        {

            readNumberField(SqlType.SQL_DOUBLE);

            if (value == null)
            {
                return null;
            }

            /*
                    if (tokenizer.isGetThis(Token.T_DIVIDE)) {
                        s = tokenizer.getString();

                        // parse simply to ensure it's a number
                        double ii = JavaSystem.parseDouble(s);

                        if (i == 0E0) {
                            i = Double.NaN;
                        } else if (i == -1E0) {
                            i = Double.NEGATIVE_INFINITY;
                        } else if (i == 1E0) {
                            i = Double.POSITIVE_INFINITY;
                        }
                    }
            */
            return Convert.ToDouble(value);
        }

        protected override decimal? readDecimal(SqlType type)
        {

            readNumberField(type);

            if (value == null)
            {
                return null;
            }

            return Convert.ToDecimal(value); ;
        }

        protected override TimeData readTime(SqlType type)
        {

            readField();

            if (value == null)
            {
                return null;
            }

            return scanner.newTime((String)value);
        }

        protected override TimestampData readDate(SqlType type)
        {

            readField();

            if (value == null)
            {
                return null;
            }

            return scanner.newDate((String)value);
        }

        protected override TimestampData readTimestamp(SqlType type)
        {

            readField();

            if (value == null)
            {
                return null;
            }

            return scanner.newTimestamp((String)value);
        }

        protected override IntervalMonthData readYearMonthInterval(SqlType type)
        {

            readField();

            if (value == null)
            {
                return null;
            }

            return (IntervalMonthData)scanner.newInterval((String)value,
                    (IntervalType)type);
        }

        protected override IntervalSecondData readDaySecondInterval(SqlType type)
        {

            readField();

            if (value == null)
            {
                return null;
            }

            return (IntervalSecondData)scanner.newInterval((String)value,
                    (IntervalType)type);
        }

        protected override Boolean? readBoolean()
        {

            readFieldPrefix();
            scanner.scanNext();

            String token = scanner.getString();

            value = null;

            if (token.Equals(Tokens.T_TRUE, StringComparison.OrdinalIgnoreCase))
            {
                value = true;
            }
            else if (token.Equals(Tokens.T_FALSE, StringComparison.OrdinalIgnoreCase))
            {
                value = false;
            }

            return (Boolean)value;
        }

        protected override Object readOther()
        {

            readFieldPrefix();

            if (scanner.scanNull())
            {
                return null;
            }

            scanner.scanBinaryStringWithQuote();

            if (scanner.getTokenType() == Tokens.X_MALFORMED_BINARY_STRING)
            {
                throw Error.error(ErrorCode.X_42587);
            }

            value = scanner.getValue();

            return new OtherData(((BinaryData)value).getBytes());
        }

        protected override BinaryData readBit()
        {

            readFieldPrefix();

            if (scanner.scanNull())
            {
                return null;
            }

            scanner.scanBitStringWithQuote();

            if (scanner.getTokenType() == Tokens.X_MALFORMED_BIT_STRING)
            {
                throw Error.error(ErrorCode.X_42587);
            }

            value = scanner.getValue();

            return (BinaryData)value;
        }

        protected override BinaryData readBinary()
        {

            readFieldPrefix();

            if (scanner.scanNull())
            {
                return null;
            }

            scanner.scanBinaryStringWithQuote();

            if (scanner.getTokenType() == Tokens.X_MALFORMED_BINARY_STRING)
            {
                throw Error.error(ErrorCode.X_42587);
            }

            value = scanner.getValue();

            return (BinaryData)value;
        }

        protected override ClobData readClob()
        {

            readNumberField(SqlType.SQL_BIGINT);

            if (value == null)
            {
                return null;
            }

            long id = Convert.ToInt64(value);

            return new ClobDataID(id);
        }

        protected override BlobData readBlob()
        {

            readNumberField(SqlType.SQL_BIGINT);

            if (value == null)
            {
                return null;
            }

            long id = Convert.ToInt64(value);

            return new BlobDataID(id);
        }
    }
}
